<template>
  <div ref="containerRef" class="waterfall-container">
    <div class="waterfall-list">
      <div
        v-for="(item, index) in state.cardList"
        :key="item.id"
        class="waterfall-list-item"
        :style="{
          width: `${state.cardPos[index].width}px`,
          height: `${state.cardPos[index].height}px`,
          transform: `translate(${state.cardPos[index].x}px, ${state.cardPos[index].y}px)`,
        }"
      >
        <slot name="item" :item="item" :index="index"></slot>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, useTemplateRef } from 'vue'
import { ICardItem, ICardPos, IWaterFallProps } from '@/views/waterfall/types'

const props = defineProps<IWaterFallProps>()

const containerRef = useTemplateRef<HTMLDivElement>('containerRef')
const state = reactive({
  isFinish: false,
  page: 1,
  cardWidth: 0,
  cardList: [] as ICardItem[],
  cardPos: [] as ICardPos[],
  columnHeight: new Array(props.column).fill(0) as number[],
})

// 计算卡片宽度
const calcCardWidth = () => {
  const containerWidth = containerRef.value?.clientWidth || 0
  state.cardWidth = (containerWidth - (props.column - 1) * props.gap) / props.column
}

// 获取卡片数据
const getCardList = async (page: number, pageSize: number) => {
  if (state.isFinish) {
    return
  }
  const list = await props.request(page, pageSize)
  state.page++
  if (!list.length) {
    state.isFinish = true
    return
  }
  state.cardList = [...state.cardList, ...list]
  computedCardPos(state.cardList)
}

// 计算卡片位置
const computedCardPos = (list: ICardItem[]) => {
  list.forEach((item, index) => {
    const cardHeight = Math.floor((item.height * state.cardWidth) / item.width)
    if (index < props.column) {
      state.cardPos.push({
        width: state.cardWidth,
        height: cardHeight,
        x: index ? (state.cardWidth + props.gap) * index : 0,
        y: 0,
      })
      state.columnHeight[index] = cardHeight + props.gap
    } else {
      const { minIndex, minHeight } = minColumn.value
      state.cardPos.push({
        width: state.cardWidth,
        height: cardHeight,
        x: minIndex ? (state.cardWidth + props.gap) * minIndex : 0,
        y: minHeight,
      })
      state.columnHeight[minIndex] += cardHeight + props.gap
    }
  })
}

onMounted(() => {
  if (containerRef.value) {
    calcCardWidth()
    getCardList(state.page, props.pageSize)
  }
})

// 计算最小列高度和卡片位置
const minColumn = computed(() => {
  let minIndex = -1,
    minHeight = Infinity

  state.columnHeight.forEach((item, index) => {
    if (item < minHeight) {
      minHeight = item
      minIndex = index
    }
  })

  return {
    minIndex,
    minHeight,
  }
})
</script>

<style lang="scss" scoped>
.waterfall {
  &-container {
    width: 100%;
    height: 100%;
    overflow-y: scroll;
    overflow-x: hidden;
    .waterfall-list {
      width: 100%;
      position: relative;
      &-item {
        position: absolute;
        top: 0;
        left: 0;
      }
    }
  }
}
</style>
